package net.entelijan.cobean.core;

import java.sql.Date;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

import javax.xml.datatype.XMLGregorianCalendar;

import net.entelijan.cobean.util.DateConverter;
import net.entelijan.cobean.util.XMLGregorianCalendarConverter;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.util.ClassUtils;

public class ColumnDesc {

	private String propertyName;
	private String headerName;
	private boolean sortable = false;
	private boolean filterable = false;
	private int width = -1;
	private Comparator<?> comparator;
	private IConverter converter;

	public ColumnDesc() {
		super();
	}

	public ColumnDesc(String propertyName) {
		super();
		this.propertyName = propertyName;
	}

	public ColumnDesc(String propertyName, String headerName, boolean sortable,
			boolean filterable, int width) {
		super();
		this.propertyName = propertyName;
		this.headerName = headerName;
		this.sortable = sortable;
		this.filterable = filterable;
		this.width = width;
	}

	public ColumnDesc(String propertyName, String headerName, boolean sortable,
			boolean filterable) {
		this(propertyName, headerName, sortable, filterable, -1);
	}

	public String getPropertyName() {
		return propertyName;
	}

	public void setPropertyName(String propertyName) {
		this.propertyName = propertyName;
	}

	public String getHeaderName() {
		return headerName;
	}

	public void setHeaderName(String headerName) {
		this.headerName = headerName;
	}

	public boolean isSortable() {
		return sortable;
	}

	public void setSortable(boolean sortable) {
		this.sortable = sortable;
	}

	public int getWidth() {
		return width;
	}

	public void setWidth(int width) {
		this.width = width;
	}

	public boolean isFilterable() {
		return filterable;
	}

	public void setFilterable(boolean filterable) {
		this.filterable = filterable;
	}

	@Override
	public String toString() {
		return "ColumnDesc propertyName='" + propertyName + "' headerName='"
				+ headerName + "' sortable='" + sortable + "' filterable='"
				+ filterable + "' width='" + width + "' comparator='"
				+ comparator + "' converter='" + converter + "'";
	}

	/**
	 * Convenience method for creating a list of column descriptors that have
	 * only the 'propertyName' property defined
	 */
	public static List<ColumnDesc> createPropertyOnlyColumnDescs(
			String... propNames) {
		ArrayList<ColumnDesc> re = new ArrayList<ColumnDesc>();
		for (String propName : propNames) {
			re.add(new ColumnDesc(propName));
		}
		return re;
	}

	/**
	 * Convenience method for creating a list of column descriptors that have
	 * only the 'propertyName' property defined and that are all filterable
	 */
	public static List<ColumnDesc> createFilterablePropertyOnlyColumnDescs(
			String... propNames) {
		ArrayList<ColumnDesc> re = createBasicColumnDescs(propNames);
		for (ColumnDesc cd : re) {
			cd.setFilterable(true);
		}
		return re;
	}

	/**
	 * Convenience method for creating a list of column descriptors that have
	 * only the 'propertyName' property defined and that are all filterable and
	 * sortable. If the property name contains a ',' it is split into property
	 * name and column title (e.g. 'name,The Name').
	 */
	public static List<ColumnDesc> createFilterableSortableColumnDescs(
			String... propNames) {
		ArrayList<ColumnDesc> re = createBasicColumnDescs(propNames);
		for (ColumnDesc cd : re) {
			cd.setFilterable(true);
			cd.setSortable(true);
		}
		return re;
	}

	/**
	 * Convenience method for creating a list of column descriptors that have
	 * only the 'propertyName' property defined and that are all filterable and
	 * sortable. If the property name contains a ',' it is split into property
	 * name and column title (e.g. 'name,The Name'). The parameter rowClass is
	 * used to get extra info from the colums (e.G. Type)
	 * 
	 */
	public static List<ColumnDesc> createFilterableSortableColumnDescs(
			Class<?> rowClass, String... propNames) {
		ArrayList<ColumnDesc> re = createBasicColumnDescs(propNames);
		BeanWrapper wrapper = new BeanWrapperImpl(rowClass);
		for (ColumnDesc cd : re) {
			cd.setConverter(createConverter(cd.propertyName, wrapper));
			cd.setFilterable(true);
			cd.setSortable(true);
		}
		return re;
	}

	private static IConverter createConverter(String propertyName,
			BeanWrapper wrapper) {
		IConverter re = null;
		Class<?> propertyType = wrapper.getPropertyType(propertyName);
		if (ClassUtils.isAssignable(Date.class, propertyType)) {
			re = new DateConverter();
		} else if (ClassUtils.isAssignable(XMLGregorianCalendar.class,
				propertyType)) {
			re = new XMLGregorianCalendarConverter();
		}
		return re;
	}

	private static ArrayList<ColumnDesc> createBasicColumnDescs(
			String... propNames) {
		ArrayList<ColumnDesc> re = new ArrayList<ColumnDesc>();
		for (String propName : propNames) {
			ColumnDesc cd = new ColumnDesc();
			if (propName.indexOf(",") >= 0) {
				String[] propHeading = propName.split(",");
				cd.setPropertyName(propHeading[0]);
				cd.setHeaderName(propHeading[1]);
			} else {
				cd.setPropertyName(propName);
				cd.setHeaderName(propName);
			}
			re.add(cd);
		}
		return re;
	}

	public Comparator<?> getComparator() {
		return comparator;
	}

	public void setComparator(Comparator<?> comparator) {
		this.comparator = comparator;
	}

	public IConverter getConverter() {
		return converter;
	}

	public void setConverter(IConverter converter) {
		this.converter = converter;
	}

}
